#ifndef __M_LOG_H__
#define __M_LOG_H__

#include "util.hpp"
#include "level.hpp"
#include "message.hpp"
#include "formatter.hpp"
#include "sink.hpp"
#include "looper.hpp"
#include <vector>
#include <list>
#include <atomic>
#include <unordered_map>
#include <cstdarg>
#include <type_traits>

namespace cl{
class SyncLogger;
class AsyncLogger;

/**
 * @brief Logger 类用于管理和记录不同级别的日志。
 *
 * 该类是日志系统的核心组件，负责提供不同级别的日志记录接口。它支持多线程环境中的日志输出，并能够
 * 动态地处理日志级别、格式、日志输出位置等配置。通过该类，可以将日志信息输出到控制台、文件、远程服务器等。
 *
 * 日志记录级别：DEBUG, INFO, WARN, ERROR, FATAL。
 * 
 * @note 该类提供了线程安全的接口，用于在并发环境中记录日志。
 */
class Logger{
public:
    // 日志器类型枚举，区分同步和异步日志器
    enum class Type {
        LOGGER_SYNC = 0,
        LOGGER_ASYNC
    };
    using ptr = std::shared_ptr<Logger>;

    // 构造函数，初始化日志器的名称、格式器、输出目标和日志级别
    Logger(const std::string &name,
        Formatter::ptr formatter,
        const std::vector<LogSink::ptr>& sinks,
        LogLevel::value level = LogLevel::value::DEBUG)
        :_name(name), _formatter(formatter), 
        _sinks(sinks.begin(), sinks.end()), _level(level){}
    
    std::string LoggerName() { return _name; }
    LogLevel::value loggerLevel() { return _level; }

    /* 各种级别的日志记录函数，接受文件名、行号和格式化字符串 */
   void debug(const std::string &file, size_t line, const std::string &fmt, ...){
        if (LogLevel::value::DEBUG < _level) { return; }

        va_list ap;
        va_start(ap, fmt);
        char *res;
        int ret = vasprintf(&res, fmt.c_str(), ap);
        if (ret == -1) {
            std::cout << "vasprintf failed" << std::endl;
            return;
        }
        va_end(ap);

        serialize(LogLevel::value::DEBUG, file, line, res);
        free(res); // vsprintf内部会动态开辟空间给res
    }

    void info(const std::string &file, size_t line, const std::string &fmt, ...){
        if (LogLevel::value::INFO < _level) { return; }
        va_list ap;
        va_start(ap, fmt);
        char *res;
        int ret = vasprintf(&res, fmt.c_str(), ap);
        if (ret == -1) {
            std::cout << "vasprintf failed" << std::endl;
            return;
        }
        va_end(ap);

        serialize(LogLevel::value::INFO, file, line, res);
        free(res); // vsprintf内部会动态开辟空间给res
    }

    void warn(const std::string &file, size_t line, const std::string &fmt, ...)
    {
        // 判断输出等级
        if (LogLevel::value::WARN < _level)
            return;

        // 解析不定参数
        va_list ap;
        va_start(ap, fmt);
        char *res;
        int ret = vasprintf(&res, fmt.c_str(), ap);
        if (ret == -1)
        {
            std::cout << "vasprintf failed" << std::endl;
            return;
        }
        va_end(ap);

        serialize(LogLevel::value::WARN, file, line, res);
        free(res); // vsprintf内部会动态开辟空间给res
    }

    void error(const std::string &file, size_t line, const std::string &fmt, ...){
        if (LogLevel::value::ERROR < _level) { return; }

        va_list ap;
        va_start(ap, fmt);
        char *res;
        int ret = vasprintf(&res, fmt.c_str(), ap);
        if (ret == -1) {
            std::cout << "vasprintf failed" << std::endl;
            return;
        }
        va_end(ap);

        serialize(LogLevel::value::ERROR, file, line, res);
        free(res); // vsprintf内部会动态开辟空间给res
    }

    void fatal(const std::string &file, size_t line, const std::string &fmt, ...){
        if (LogLevel::value::FATAL < _level) { return; }

        va_list ap;
        va_start(ap, fmt);
        char *res;
        int ret = vasprintf(&res, fmt.c_str(), ap);
        if (ret == -1) {
            std::cout << "vasprintf failed" << std::endl;
            return;
        }
        va_end(ap);
        serialize(LogLevel::value::FATAL, file, line, res);
        free(res); // vsprintf内部会动态开辟空间给res
    }

    // 日志器构建器基类，采用建造者模式创建日志器
    class Builder{
    public:
        using ptr = std::shared_ptr<Builder>;
        Builder():_level(LogLevel::value::DEBUG), _logger_type(Logger::Type::LOGGER_SYNC){}

        void buildLoggerName(const std::string &name) { _logger_name = name; }; // 设置日志器名称
        void buildLoggerLevel(LogLevel::value level) { _level = level; }        // 设置日志级别
        void buildLoggerType(Logger::Type type) { _logger_type = type; }        // 设置日志器类型(同步或异步)
        void buildFormatter(const std::string pattern) { _formatter = std::make_shared<Formatter>(pattern); }   // 设置日志格式器
        void buildFormatter(const Formatter::ptr &formatter) { _formatter = formatter; }

        // 添加日志输出目标（Sink）
        template<typename SinkType, typename ...Args>
        void buildSink(Args&& ...args) {
            auto sink = SinkFactory::create<SinkType>(std::forward<Args>(args)...);
            _sinks.push_back(sink);
        }

        // 构建日志器（子类实现）
        virtual Logger::ptr build() = 0;
        
    protected:
        Logger::Type _logger_type;          // 日志器类型
        std::string _logger_name;           // 日志器名称
        // std::atomic<LogLevel::value> _level;// 日志级别
        LogLevel::value _level;// 日志级别
        Formatter::ptr _formatter;          // 日志格式器
        std::vector<LogSink::ptr> _sinks;   // 日志输出目标集合
    };

protected:
    void serialize(LogLevel::value level, const std::string &file, size_t line, char *str){
        // 构建Logmsg对象
        LogMsg msg(_name, file, line, str, level);

        // 获取格式化后的字符串
        std::stringstream ss;
        _formatter->format(ss, msg);

        // 日志落地
        logIt(ss.str().c_str(), ss.str().size());
    }
    // 子类实现具体的日志输出逻辑
    virtual void logIt(const std::string &msg, size_t len) = 0;

protected:
    std::mutex _mutex;                  // 互斥锁
    std::string _name;                  // 日志器名称
    Formatter::ptr _formatter;          // 日志格式器
    std::atomic<LogLevel::value> _level;// 日志级别（使用原子操作，支持线程安全）
    // LogLevel::value _level;// 日志级别（使用原子操作，支持线程安全）
    std::vector<LogSink::ptr> _sinks;   // 日志输出目标集合
}; // class Logger

/**
 * @brief 异步日志器类，异步输出日志消息
 * 
 * 该类继承自 Logger，提供同步方式的日志记录实现。日志消息会在调用时立即格式化并输出到指定的日志目标（Sink）。
 * 适用于对实时性要求较高的场景。
 * 
 * @note SyncLogger 使用互斥锁保证线程安全，在多线程环境下直接输出日志。
 */
class SyncLogger : public Logger{
public:
    using ptr = std::shared_ptr<SyncLogger>;

    SyncLogger(const std::string &name,
        Formatter::ptr formatter,
        std::vector<LogSink::ptr> &sinks,
        const LogLevel::value level = LogLevel::value::DEBUG)
        :Logger(name, formatter, sinks, level){
        std::cout << "同步日志器 [" << name << "] 创建成功，级别：" << LogLevel::toString(level) << "\n";
    }
private:
    // 实现日志输出，直接将格式化后的日志消息输出到所有的Sink
    virtual void logIt(const std::string &msg, size_t len) override {
        std::unique_lock<std::mutex> lock(_mutex);
        if(_sinks.empty()) { return; }
        for(const auto &it : _sinks){
            it->log(msg.c_str(), msg.size());
        }
    }
}; // class SyncLogger

/**
 * @brief 异步日志构造器，异步输出日志消息。
 * 
 * 该类继承自Logger，提供异步方式的日志记录实现。日志消息会被推送到异步循环器中，由后台线程进行格式化和输出，
 * 从而减少主线程的阻塞，提高系统的性能。
 * 适用于对性能要求较高的场景。
 * 
 * @note AsyncLogger 使用异步循环器（AsyncLooper）处理日志输出，主线程将日志消息推送到队列中即可。
 */
class AsyncLogger : public Logger{
public:
    using ptr = std::shared_ptr<AsyncLogger>;
    
    AsyncLogger(const std::string &name,
        Formatter::ptr formatter,
        std::vector<LogSink::ptr> &sinks,
        const LogLevel::value level = LogLevel::value::DEBUG)
        :Logger(name, formatter, sinks, level),
        _looper(std::make_shared<AsyncLooper>(
            std::bind(&AsyncLogger::backendLogIt, this, std::placeholders::_1))){
            std::cout << "异步日志器 [" << name << "] 创建成功，级别：" << LogLevel::toString(level) << "\n";
    }
protected:
    // 实现日志输出，将日志消息推送到异步循环器中
    virtual void logIt(const std::string &msg, size_t len) override {
        _looper->push(msg);
    }

    // 后台线程实现处理日志输出
    void backendLogIt(Buffer &msg){
        if(_sinks.empty()) { return; }
        for(const auto &it : _sinks){
            it->log(msg.begin(), msg.readAbleSize());
        }
    }
protected:
    AsyncLooper::ptr _looper;   // 异步循环器，用于异步处理日志输出
}; // class AsyncLogger

/**
 * @brief 本地日志构造器，用于创建不加入全局管理器的日志器。
 * 
 * 该类继承自 Logger::Builder，采用建造者模式，提供灵活的接口来构建Logger实例。
 * 通过设置日志器名称、类型、级别、格式器和输出目标，可以创建定制化的日志器。
 * 创建的日志器不会被注册到全局的 LoggerManager 中。
 * 
 * @note LocalLoggerBuilder 适用于需要独立管理的日志器，避免与全局日志器产生冲突。
*/
class LocalLoggerBuilder : public Logger::Builder{
public:
    virtual Logger::ptr build() override {
        assert(_logger_name.empty() == false);
        if(_formatter.get() == nullptr){
            // std::cout << "日志器 [" << _logger_name << "] 未指定日志格式器, 默认设置为 [ %d{%H:%M:%S}%T%t%T[%p]%T[%c]%T%f:%l%T%m%n ]!\n";
            _formatter = std::make_shared<Formatter>();
        }
        if(_sinks.empty()){
            // std::cout << "日志器 [" << _logger_name << "] 未指定输出目标, 默认设置为标准输出!\n";
            _sinks.push_back(std::make_shared<StdoutSink>());
        }
        Logger::ptr lp;
        if(_logger_type == Logger::Type::LOGGER_ASYNC){
            lp = std::make_shared<AsyncLogger>(_logger_name, _formatter, _sinks, _level);
        }
        else{
            lp = std::make_shared<SyncLogger>(_logger_name, _formatter, _sinks, _level);
        }
        return lp;
    }
}; // class LocalLoggerBuilder

/**
 * @brief LoggerManager 类用于管理所有日志记录器实例。
 * 
 * 该类是日志系统的管理类，负责维护所有日志记录器（Logger）的生命周期和配置。它通过名称索引不同的日志记录器，
 * 允许用户根据名称获取相应的日志器实例。`LoggerManager` 通常是单例模式，确保全局只有一个管理器来管理日志器。
 * 
 * @note LoggerManager 提供线程安全的接口，支持在多线程环境下安全地添加和获取日志器。
 */
class LoggerManager{
public:
    // 获取 LoggerManager 的唯一实例
    static LoggerManager& getInstance(){
        static LoggerManager lm;
        return lm;
    }

    // 检查是否存在指定名称的日志器  
    bool hasLogger(const std::string &name){
        std::unique_lock<std::mutex> lock(_mutex);
        return _loggers.find(name) != _loggers.end();
    }

    // 添加日志器到管理器中
    void addLogger(const std::string &name, const Logger::ptr logger){
        std::unique_lock<std::mutex> lock(_mutex);
        // _loggers.insert(std::make_pair(name, logger));
        _loggers[name] = logger;
    }

    // 获取指定名称的日志器
    Logger::ptr getLogger(const std::string &name){
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _loggers.find(name);
        if(it == _loggers.end()){
            return Logger::ptr();
        }
        return it->second;
    }

    // 获取根日志器
    Logger::ptr rootLogger(){
        std::unique_lock<std::mutex> lock(_mutex);
        return _root_logger;
    }

private:
    // 私有构造函数，初始化根日志器
    LoggerManager(){
        std::unique_ptr<LocalLoggerBuilder> builder(new LocalLoggerBuilder());
        builder->buildLoggerName("root");
        builder->buildLoggerType(Logger::Type::LOGGER_SYNC);
        _root_logger = builder->build();
        // _root_logger = nullptr;
        _loggers["root"] = _root_logger;
    }
    // 禁用拷贝构造和赋值操作
    LoggerManager(const LoggerManager&) = delete;
    LoggerManager &operator=(const LoggerManager&) = delete;

private:
    std::mutex _mutex;          // 互斥锁，保护共享资源
    Logger::ptr _root_logger;   // 跟日志器
    std::unordered_map<std::string, Logger::ptr> _loggers;  // 日志器集合
}; // class LoggerManager

/**
 * @brief 全局日志构造器，用于创建并加入全局管理器的日志器。
 * 
 * 该类继承自 Logger::Builder，提供创建 Logger 实例的接口，并在创建后将其注册到全局的 LoggerManager 中。
 * 通过该构造器创建的日志器类可以在应用程序的任何地方通过LoggerManager
*/
class GlobalLoggerBuilder : public Logger::Builder{
public:
    virtual Logger::ptr build() override {
        assert(_logger_name.empty() == false);
        assert(LoggerManager::getInstance().hasLogger(_logger_name) == false);
        if(_formatter.get() == nullptr){
            _formatter = std::make_shared<Formatter>();
        }
        if(_sinks.empty()){
            _sinks.push_back(std::make_shared<StdoutSink>());
        }
        Logger::ptr logger;
        if(_logger_type == Logger::Type::LOGGER_ASYNC){
            logger = std::make_shared<AsyncLogger>(_logger_name, _formatter, _sinks, _level);
        }
        else{
            logger = std::make_shared<SyncLogger>(_logger_name, _formatter, _sinks, _level);
        }
        LoggerManager::getInstance().addLogger(_logger_name, logger);
        return logger;
    }
}; // class GlobalLoggerBuilder
}
#endif